package com.xyl.audio.utils;

import android.util.Log;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.Arrays;

/**
 * @author xyl on 2019/7/15.
 */
public class Utils {
    public final static String TAG = "Utils";

    /**
     * wav文件转pcm
     *
     * @param wavFilePath
     * @return
     */
    public static byte[] wavToPcm(String wavFilePath) {
        FileInputStream fileInputStream;
        byte[] pcmByte = new byte[0];
        try {
            fileInputStream = new FileInputStream(wavFilePath);
            byte[] wavByte = inputStreamToByte(fileInputStream);
            pcmByte = Arrays.copyOfRange(wavByte, 0, wavByte.length);
            CloseUtils.closeIOQuietly(fileInputStream);

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return pcmByte;
    }

    public static void byteToFile(byte[] bytes, String path) {
        try {
            // 根据绝对路径初始化文件
            File localFile = new File(path);
            if (!localFile.exists()) {
                localFile.createNewFile();
            }
            // 输出流
            OutputStream os = new FileOutputStream(localFile);
            os.write(bytes);
            os.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * @param fis
     * @return
     * @throws IOException
     */
    private static byte[] inputStreamToByte(FileInputStream fis) throws IOException {
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        long size = fis.getChannel().size();
        int countLength = countLength(fis);
        //        、、=====================================
        Log.d(TAG, "  long size===" + size);
        byte[] buffer = null;
        if (size <= Integer.MAX_VALUE) {
            buffer = new byte[(int) size];
        } else {
            buffer = new byte[8];
            for (int ix = 0; ix < 8; ++ix) {
                int offset = 64 - (ix + 1) * 8;
                buffer[ix] = (byte) ((size >> offset) & 0xff);
            }
        }
        int len;
        while ((len = fis.read(buffer)) != -1) {
            bos.write(buffer, 0, len);
        }
        byte[] data = bos.toByteArray();
        CloseUtils.closeIOQuietly(bos);
        return data;
    }

    /**
     * 打印wav头(44字节)
     *
     * @param fis
     * @return
     * @throws IOException
     */
    private static int countLength(FileInputStream fis) throws IOException {

        byte[] intValue = new byte[4];
        byte[] shortValue = new byte[2];
        //4
        String mChunkID = "" + (char) fis.read() + (char) fis.read() + (char) fis.read() + (char) fis.read();
        Log.d(TAG, "Read file chunkID:" + mChunkID);//chunkID

        //4
        fis.read(intValue);
        int mChunkSize = byteArrayToInt(intValue);
        Log.d(TAG, "Read file chunkSize:" + mChunkSize);//20646

        //4
        String mFormat = "" + (char) fis.read() + (char) fis.read() + (char) fis.read() + (char) fis.read();
        Log.d(TAG, "Read file format:" + mFormat);//WAVE

        //4
        String mSubChunk1ID = "" + (char) fis.read() + (char) fis.read() + (char) fis.read() + (char) fis.read();
        Log.d(TAG, "Read fmt chunkID:" + mSubChunk1ID);//fmt

        //4
        fis.read(intValue);
        int mSubChunk1Size = byteArrayToInt(intValue);
        Log.d(TAG, "Read fmt chunkSize:" + mSubChunk1Size);//16

        //2
        fis.read(shortValue);
        int mAudioFormat = byteArrayToShort(shortValue);
        Log.d(TAG, "Read audioFormat:" + mAudioFormat);//1

        //2
        fis.read(shortValue);
        int mNumChannel = byteArrayToShort(shortValue);
        Log.d(TAG, "Read channel number:" + mNumChannel);//1

        //4
        fis.read(intValue);
        int mSampleRate = byteArrayToInt(intValue);
        Log.d(TAG, "Read samplerate:" + mSampleRate);//44100

        //4
        fis.read(intValue);
        int mByteRate = byteArrayToInt(intValue);
        Log.d(TAG, "Read byterate:" + mByteRate); //16000

        //2
        fis.read(shortValue);
        int mBlockAlign = byteArrayToShort(shortValue);
        Log.d(TAG, "Read blockalign:" + mBlockAlign);//2

        //2
        fis.read(shortValue);
        int mBitsPerSample = byteArrayToShort(shortValue);
        Log.d(TAG, "Read bitspersample:" + mBitsPerSample); //16

        //4
        String mSubChunk2ID = "" + (char) fis.read() + (char) fis.read() + (char) fis.read() + (char) fis.read();
        Log.d(TAG, "Read data chunkID:" + mSubChunk2ID);//LIST

        //4
        fis.read(intValue);
        int mSubChunk2Size = byteArrayToInt(intValue);
        Log.d(TAG, "Read data chunkSize:" + mSubChunk2Size);//chunkSize122

        Log.d(TAG, "Read wav file success !");


        return mSubChunk2Size;
    }

    private static short byteArrayToShort(byte[] b) {
        return ByteBuffer.wrap(b).order(ByteOrder.LITTLE_ENDIAN).getShort();
    }

    private static int byteArrayToInt(byte[] b) {
        return ByteBuffer.wrap(b).order(ByteOrder.LITTLE_ENDIAN).getInt();
    }

    public static short[] bytesToShort(byte[] bytes) {
        short[] shorts = new short[bytes.length / 2];
        ByteBuffer.wrap(bytes).order(ByteOrder.LITTLE_ENDIAN).asShortBuffer().get(shorts);
        return shorts;
    }

    public static byte[] shortToBytes(short[] shorts) {
        byte[] bytes = new byte[shorts.length * 2];
        ByteBuffer.wrap(bytes).order(ByteOrder.LITTLE_ENDIAN).asShortBuffer().put(shorts);
        return bytes;
    }

    /**
     * short 转byte
     *
     * @param sData
     * @return
     */
    public static byte[] short2byte(short[] sData) {
        int shortArraySize = sData.length;
        byte[] bytes = new byte[shortArraySize * 2];

        for (int i = 0; i < shortArraySize; i++) {
            bytes[i * 2] = (byte) (sData[i] & 0x00FF);
            bytes[(i * 2) + 1] = (byte) (sData[i] >> 8);
            sData[i] = 0;
        }
        return bytes;
    }

}
